package com.zhijian.medical.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.zhijian.medical.dao.local.QcMapper;
import com.zhijian.medical.entity.po.Qc;
import com.zhijian.medical.entity.po.QcData;
import com.zhijian.medical.entity.vo.request.QcDataSearchVo;
import com.zhijian.medical.entity.vo.request.QcSearchVo;
import com.zhijian.medical.entity.vo.request.QcStatisticsSearchVo;
import com.zhijian.medical.entity.vo.request.QcUpdateVo;
import com.zhijian.medical.entity.vo.response.QcDataVo;
import com.zhijian.medical.entity.vo.response.QcStatistics2Vo;
import com.zhijian.medical.entity.vo.response.QcStatisticsVo;
import com.zhijian.medical.entity.vo.response.QcVo;
import com.zhijian.medical.service.QcDataService;
import com.zhijian.medical.service.QcService;
import com.zhijian.medical.util.AssertUtil;
import com.zhijian.medical.util.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 质控业务处理层
 *
 * @author HCG
 * @version: 1.0
 * @date 2022-10-19 13:36:43
 */
@Slf4j
@Service
public class QcServiceImpl implements QcService {

    @Autowired
    private QcMapper mapper;

    @Autowired
    private QcDataService qcDataService;

    @Override
    public Qc selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public QcVo selectVoById(Long id) {
        return mapper.selectVoById(id);
    }

    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public Long insert(Qc qc) {
        Date now = new Date();
        qc.setCreateTime(now);
        qc.setUpdateTime(now);
        return mapper.insert(qc) > 0 ? qc.getId() : 0L;
    }

    @Override
    public boolean update(Qc qc) {
        Date now = new Date();
        qc.setUpdateTime(now);
        return mapper.updateByPrimaryKey(qc) != 0;
    }

    @Override
    public Integer count(QcSearchVo qcSearchVo) {
        return mapper.count(qcSearchVo);
    }

    @Override
    public List<QcVo> selectList(QcSearchVo qcSearchVo) {
        return mapper.selectList(qcSearchVo);
    }

    @Override
    public Page<QcVo> selectPage(QcSearchVo qcSearchVo) {
        //先直接查总数
        int count = count(qcSearchVo);
        //分页
        Page<QcVo> page = new Page<>(true, count, qcSearchVo.getPageNum(), qcSearchVo.getPageSize());
        qcSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<QcVo> responseVos = this.selectList(qcSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Override
    public List<QcVo> render(QcSearchVo qcSearchVo) {

        if (Objects.nonNull(qcSearchVo.getParentId())) {
            return this.selectList(qcSearchVo);
        }
        //父数据
        List<QcVo> parentList = this.selectList(QcSearchVo.builder()
                .parentId(0L)
                .build());
        if (CollectionUtil.isNotEmpty(parentList)) {
            parentList.forEach(p -> {
                List<QcVo> l = selectList(QcSearchVo.builder()
                        .parentId(p.getId())
                        .date(qcSearchVo.getDate())
                        .build());
                p.setChildren(l);
            });
        }
        return parentList;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean updateAll(List<QcUpdateVo> qcUpdateVos) {

        if (CollectionUtil.isNotEmpty(qcUpdateVos)) {
            qcUpdateVos.forEach(c -> {
                List<QcDataVo> qcDataVos = qcDataService.selectList(QcDataSearchVo.builder()
                        .qcId(c.getId())
                        .date(c.getDate())
                        .build());
                if (CollectionUtil.isEmpty(qcDataVos)) {
                    //空，保存
                    qcDataService.insert(QcData.builder()
                            .qcId(c.getId())
                            .date(c.getDate())
                            .status(c.getStatus())
                            .value(c.getValue())
                            .build());
                } else {
                    //修改
                    qcDataService.updateValueAndStatusByQcIdAndDate(c.getValue(), c.getStatus(), c.getId(), c.getDate());
                }
            });
        }

        return true;
    }

    @Override
    public List<QcStatisticsVo> statistics(QcStatisticsSearchVo qcStatisticsSearchVo) {
        if (StringUtils.isBlank(qcStatisticsSearchVo.getStartDate())) {
            //如果开始日期为空，取今年第一个月
            qcStatisticsSearchVo.setStartDate(String.format("%s-01", DateUtil.year(new Date())));
        }
        if (StringUtils.isBlank(qcStatisticsSearchVo.getEndDate())) {
            //如果结束日期为空，取今年第一个月
            qcStatisticsSearchVo.setEndDate(String.format("%s-12", DateUtil.year(new Date())));
        }
        DateTime startDate = DateUtil.parse(qcStatisticsSearchVo.getStartDate(), "yyyy-MM");
        DateTime endDate = DateUtil.parse(qcStatisticsSearchVo.getEndDate(), "yyyy-MM");
        AssertUtil.check(startDate.after(endDate) || startDate.compareTo(endDate) == 0, "结束日期必须在开始日期后");
        List<DateTime> dateTimes = DateUtil.rangeToList(startDate, endDate, DateField.MONTH);
        return dateTimes.stream().map(dateTime -> {
            QcStatisticsVo qcStatisticsVo = new QcStatisticsVo();
            qcStatisticsVo.setDate(DateUtil.format(dateTime, "yyyy-MM"));
            List<QcDataVo> qcDataVoList = qcDataService.selectList(QcDataSearchVo.builder()
                    .qcId(qcStatisticsSearchVo.getQcId())
                    .date(DateUtil.format(dateTime, "yyyy-MM"))
                    .build());

            qcStatisticsVo.setNumber(CollectionUtil.isNotEmpty(qcDataVoList) && StringUtils.isNotBlank(qcDataVoList.get(0).getValue()) ? Integer.valueOf(qcDataVoList.get(0).getValue()) : 0);
            return qcStatisticsVo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<QcStatistics2Vo> statistics2(QcStatisticsSearchVo qcStatisticsSearchVo) {
        List<QcStatisticsVo> statistics = this.statistics(qcStatisticsSearchVo);
        if (CollectionUtil.isNotEmpty(statistics)) {
            return statistics.stream().map(s -> {
                QcStatistics2Vo q = new QcStatistics2Vo();
                q.setName(s.getDate());
                q.setValue(s.getNumber());
                return q;
            }).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public void export(QcStatisticsSearchVo qcStatisticsSearchVo, HttpServletResponse response) {
        Qc qc = selectById(qcStatisticsSearchVo.getQcId());
        AssertUtil.notNull(qc, "此质控标准不存在或者已被删除");

        List<QcStatisticsVo> statisticsList = this.statistics(qcStatisticsSearchVo);
        ExcelWriter writer = ExcelUtil.getWriter(true);

        writer.addHeaderAlias("date", "日期")
                .addHeaderAlias("number", "数量");
        // 合并单元格后的标题行，使用默认标题样式
        writer.merge(1, String.format("%s数据统计", qc.getName()));
        // 默认的，未添加alias的属性也会写出，如果想只写出加了别名的字段，可以调用此方法排除之
        writer.setOnlyAlias(true);
        writer.write(statisticsList, true);

        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", String.format("attachment;filename=%s.xlsx", "题库记录"));
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            writer.flush(out, true);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
            IoUtil.close(out);
        }
    }

    @Override
    public List<QcVo> selectChildrenByParentName(String parentName) {
        return mapper.selectChildrenByParentName(parentName);
    }

}